package com.luoy.sca4;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TreeMap;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

public class SCA4Demo {

    private final static Charset UTF8 = StandardCharsets.UTF_8;
    private final static String SECRET_ID = "3aee4a452d444b0a803648******";
    private final static String SECRET_KEY = "6E335EA5927F60610200EECE2297C3D757B79F67C47E1DA0893F00144******";
    private final static String CT_JSON = "application/json; charset=utf-8";

    static String payload1 = "{\"ID\":\"3453535\",\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"自定义策略-1666765456282\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:ListBucket\",\"s3:HeadBucket\",\"s3:GetObject\",\"s3:GetObjectVersion\"],\"Resource\":[\"arn:aws:s3:::test\",\"arn:aws:s3:::test/*\"]}]}";



    public static byte[] hmac256(byte[] key, String msg) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
        mac.init(secretKeySpec);
        return mac.doFinal(msg.getBytes(UTF8));
    }

    public static String sha256Hex(String s) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] d = md.digest(s.getBytes(UTF8));
        System.out.println(d);
        return DatatypeConverter.printHexBinary(d).toLowerCase();
    }


    public static void main(String[] args) throws Exception {
        String service = "oss";
        String host = "oss.sugoncloud.com";
        String region = "cn-east-1";
        String project = "f50f426c8d414103ad29e024fc7bce0f";
        String action = "PutBucketPolicy";
        String algorithm = "SCA4-HMAC-SHA256";
        String timestamp = "1551113065";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        // 注意时区，否则容易出错
        sdf.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));
        String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));

        // ************* 步骤 1：拼接规范请求串 *************
        String httpRequestMethod = "POST";
        String canonicalUri = "/";
        String canonicalQueryString = "page_num=1&page_size=10&server_id=&exist_in_garbage=false&project_id=f50f426c8d414103ad29e024fc7bce0f&name=&host=&server_type=1";
        String canonicalHeaders = "content-type:application/json; charset=utf-8\nx-sca4-action:putbucketpolicy\n";
        String signedHeaders = "content-type;x-sca4-action";
        String payload = "{\"ID\":\"3453535\",\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"自定义策略-1666765456282\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:ListBucket\",\"s3:HeadBucket\",\"s3:GetObject\",\"s3:GetObjectVersion\"],\"Resource\":[\"arn:aws:s3:::test\",\"arn:aws:s3:::test/*\"]}]}";

        String canonicalRequest = httpRequestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
                + canonicalHeaders + "\n" + signedHeaders;
        if(!"GET".equalsIgnoreCase(httpRequestMethod)) {
            String hashedRequestPayload = sha256Hex(payload);
            canonicalRequest = httpRequestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
                    + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;
        }
        System.out.println(canonicalRequest);



//        AWS4-HMAC-SHA256 Credential=a7030685172f4cd588df5094f4807179/2019-02-25/region/oss/sca4_request,SignedHeaders=date;host;user-agent;x-amz-content-sha256,Signature=4dca3c48e26a11643ec037335a61b5990ac3f397d579e931cdbdef5d94692640

        // ************* 步骤 2：拼接待签名字符串 *************
        String credentialScope = date + "/"+ region+"/"+ service + "/" + "sca4_request";
        String hashedCanonicalRequest = sha256Hex(canonicalRequest);
        String stringToSign = algorithm + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
        System.out.println("stringToSign："+stringToSign);

        // ************* 步骤 3：计算签名 *************
        byte[] secretDate = hmac256(("SCA4" + SECRET_KEY).getBytes(UTF8), date);
        byte[] secretService = hmac256(secretDate, service);
        byte[] secretSigning = hmac256(secretService, "sca4_request");
        String signature = DatatypeConverter.printHexBinary(hmac256(secretSigning, stringToSign)).toLowerCase();
        System.out.println(signature);

        // ************* 步骤 4：拼接 Authorization *************
        String authorization = algorithm + " " + "Credential=" + SECRET_ID + "/" + credentialScope + ", "
                + "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
        System.out.println(authorization);

        TreeMap<String, String> headers = new TreeMap<String, String>();
        headers.put("Authorization", authorization);
        headers.put("Content-Type", CT_JSON);
        headers.put("X-SCA4-Action", action);
        headers.put("X-SCA4-Date", timestamp);
        headers.put("X-SCA4-Region", region);
        headers.put("X-SCA4-Project", project);

        StringBuilder sb = new StringBuilder();
        sb.append("curl -X POST https://").append(host)
                .append(" -H \"Authorization: ").append(authorization).append("\"")
                .append(" -H \"Content-Type: application/json; charset=utf-8\"")
                .append(" -H \"X-SCA4-Action: ").append(action).append("\"")
                .append(" -H \"X-SCA4-Date: ").append(timestamp).append("\"")
                .append(" -H \"X-SCA4-Project: ").append(project).append("\"")
                .append(" -H \"X-SCA4-Region: ").append(region).append("\"")
                .append(" -d '").append(payload).append("'");
        System.out.println(sb);
    }
}
